<?php

namespace Plugins\AdminBasic\Http\Admin\Service;

use App\Interfaces\AdminRouteMenuServiceInterface;
use App\Models\Model;
use App\Util\AdminAuth;
use App\Util\Helper;
use App\Util\ImitateAop\Attributes\Transaction;
use Plugins\AdminBasic\Enums\BasicRouteEnumType;
use Sc\Util\ImitateAopProxy\AopProxyTrait;
use App\Exception\ApiMessageException;
use App\Http\Admin\Service\Traits\DestroyServiceTrait;
use App\Http\Admin\Service\Traits\StoreServiceTrait;
use App\Http\Admin\Service\Traits\SwitchServiceTrait;
use App\Http\Admin\Service\Traits\UpdateServiceTrait;
use App\Util\EasySearch;
use Plugins\AdminBasic\Models\BasicRoute;
use Sc\Util\ScTool;


/**
 * 路由菜单
 */
class RouteService implements AdminRouteMenuServiceInterface
{

    use AopProxyTrait;
    use StoreServiceTrait;
    use UpdateServiceTrait;
    use DestroyServiceTrait;
    use SwitchServiceTrait;

    /**
     * 获取模型
     */
    public function getModel(int $id = null): BasicRoute
    {
        return $id ? BasicRoute::find($id) :new BasicRoute();
    }

    public function lists(): array
    {
        $query = BasicRoute::select(['title', 'id', 'pid', 'type', 'open_type', 'route', 'weigh', 'icon',])
            ->orderByDesc('weigh')->orderBy('id');

        $data = EasySearch::create($query)->totalCancellations()->getData();

        return ['data' => ScTool::tree($data['data']->toArray())->getTreeData()];
    }


    /**
     * 获取菜单数据
     *
     * @return array
     */
    public function getMenu(): array
    {
        $routes = BasicRoute::where('type', BasicRouteEnumType::LeftMenu->value)
            ->select([
                'id as index', 'title', 'route', 'pid', 'open_type', 'icon'
            ])->orderByDesc('weigh')->orderBy('id');

        if (!AdminAuth::isSuper()) {
            $routes->whereIn('id', Helper::getContainer(RolePermissionsService::class)->getRouteIds(AdminAuth::getInfo()->role_ids));
        }
        $routes = $routes->get()->map(function (BasicRoute $route){
            $route->route = Helper::route()->correctRule($route->route);
            return $route;
        });

        return ScTool::tree($routes->toArray())->setNodeKey('index')->getTreeData();
    }

    /**
     * @return void
     * @throws InvalidArgumentException
     */
    public function afterWrite(): void
    {
        RolePermissionsService::aop(false)->cache();
    }

    public function beforeStore(&$data, Model $model)
    {
        $data['pid'] = $data['pid'] ?? 0;

        $weigh = BasicRoute::where('pid', $data['pid'])->min('weigh');
        $data['weigh'] = $weigh - 1;
    }

    /**
     * @param int $oldId
     * @param int $newId
     * @param int $isUp
     *
     * @return array
     * @throws ApiMessageException
     */
    #[Transaction]
    public function sort(int $oldId, int $newId, int $isUp): array
    {
        $old = BasicRoute::find($oldId);
        $new = BasicRoute::find($newId);

        if (!$old || !$new) {
            throw new ApiMessageException("信息错误");
        }
        if ($old->pid == $new->pid) {
            if ($old->weigh == $new->weigh) {
                $new->weigh = $new->id > $old->id ? $new->weigh + 1 : $new->weigh - 1;
            }else if($old->weigh > $new->weigh){
                BasicRoute::where('pid', $old->pid)
                    ->where('weigh', '>', $new->weigh)
                    ->where('weigh', '<', $old->weigh)
                    ->increment('weigh');
                $old->weigh = $new->weigh;
                $new->weigh++;
            }else if($old->weigh < $new->weigh){
                BasicRoute::where('pid', $old->pid)
                    ->where('weigh', '<', $new->weigh)
                    ->where('weigh', '>', $old->weigh)
                    ->decrement('weigh');
                $old->weigh = $new->weigh;
                $new->weigh--;
            }
        }else{
            if ($isUp) {
                BasicRoute::where('pid', $new->pid)
                    ->where('weigh', '<', $new->weigh)
                    ->decrement('weigh');
                $old->weigh = $new->weigh;
                $new->weigh--;
            }else{
                BasicRoute::where('pid', $new->pid)
                    ->where('weigh', '>', $new->weigh)
                    ->increment('weigh');
                $old->weigh = $new->weigh;
                $new->weigh++;
            }

            $old->pid = $new->pid;
        }

        $old->save();
        $new->save();

        return [
            'old' => $old->weigh,
            'new' => $new->weigh
        ];
    }
}